package com.shuyu.service.impl;

import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.shuyu.common.core.domain.entity.Customer;
import com.shuyu.common.enums.ProductType;
import com.shuyu.common.exception.ServiceException;
import com.shuyu.common.utils.DateUtils;
import com.shuyu.common.utils.SecurityUtils;
import com.shuyu.common.utils.StringUtils;
import com.shuyu.common.utils.aliyun.AlipayTradeAppPay;
import com.shuyu.common.utils.ip.IpUtils;
import com.shuyu.common.utils.uuid.Seq;
import com.shuyu.domain.*;
import com.shuyu.service.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;

@Service
public class PayNotifyServiceImpl implements PayNotifyService {

    @Value("${wx.pay.notifyUrl}")
    private String notifyUrl;
    @Resource
    private OrderService orderService;
    @Resource
    private ProductService productService;
    @Resource
    private CustomerWxService customerWxService;
//    @Resource
//    private Config config;
    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Resource
    private CustomerService customerService;
    @Resource
    private CustomerAssetsService customerAssetsService;
    @Resource
    private ActivityProductService activityProductService;
    @Resource
    private ActivityService activityService;
    @Resource
    private CustomerPointService customerPointService;

    @Override
    public WxPayUnifiedOrderRequest createWxOrder(int productId,HttpServletRequest request) {
        String orderSn = DateUtils.dateTimeNow()+ Seq.generateRandomInt(6);
        Product product = productService.getById(productId);
        String body = product.getName();
        int count = 1;
        double totalPrice = product.getPrice()*count;
        int fee = (int) (totalPrice*100);
        long customerId = SecurityUtils.getLoginUser().getUserId();
        Customer customer = customerService.getById(customerId);
        CustomerWx customerWx = customerWxService.getById(customer.getThirdId());
        String openId = customerWx.getOpenId();

        WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = new WxPayUnifiedOrderRequest();
        wxPayUnifiedOrderRequest.setBody(body);
        wxPayUnifiedOrderRequest.setOutTradeNo(orderSn);
        wxPayUnifiedOrderRequest.setTotalFee(fee);
        wxPayUnifiedOrderRequest.setOpenid(openId);
        String ip = IpUtils.getIpAddr(request);
        wxPayUnifiedOrderRequest.setSpbillCreateIp(ip);
        wxPayUnifiedOrderRequest.setNotifyUrl(notifyUrl+"/api/notify/wx");
        wxPayUnifiedOrderRequest.setTradeType(WxPayConstants.TradeType.APP);
        Order order = new Order(orderSn, product.getPrice(), totalPrice, productId, customer.getId(), 0, 1, new Date(), product.getSource(), product.getPropId(),count);
        orderService.save(order);
        return wxPayUnifiedOrderRequest;
    }

    @Override
    public void handleOrderNotifyResult(WxPayOrderNotifyResult notifyResult) {
        String orderSn = notifyResult.getOutTradeNo();
        if(notifyResult.getReturnCode().equals("SUCCESS")) {
            if (notifyResult.getResultCode().equals("SUCCESS")) {
                String transactionId = notifyResult.getTransactionId();
                updateOrder(1, transactionId, orderSn);
            }else {
                updateOrder(2, null, orderSn);
            }
        }else {
            updateOrder(2, null, orderSn);
        }
    }

    @Override
    public void handleAlipayOrderNotifyResult(String outTradeNo, String tradeStatus, String tradeNo) {
        threadPoolTaskExecutor.execute(new NotifyHandler(outTradeNo, tradeStatus, tradeNo));
    }

    @Override
    public void pointPay(int productId,int activityProductId) {
        Product product = productService.getOne(new LambdaQueryWrapper<Product>().eq(Product::getId,productId).eq(Product::getAuditStatus,1).eq(Product::getDelFlag,0));
        if(product == null){
            throw new ServiceException("购买商品不存在");
        }
        ActivityProduct activityProduct = activityProductService.getById(activityProductId);
        if(activityProduct == null){
            throw new ServiceException("改商品不允许积分购买");
        }

        Activity activity = activityService.getById(activityProduct.getActivityId());
        if(activity.getStartTime().after(new Date())||activity.getEndTime().before(new Date())){
            throw new ServiceException("改商品不允许积分购买!");
        }
        if(activity.getAuditStatus() != 1){
            throw new ServiceException("改商品不允许积分购买!");
        }
        long customerId = SecurityUtils.getLoginUser().getUserId();
        Customer customer = customerService.getById(customerId);
        int count = 1;
        int totalPoint = activityProduct.getPoint()*count;
        if(customer.getPoint()<totalPoint){
            throw new ServiceException("积分不足!");
        }
        String orderSn = DateUtils.dateTimeNow()+ Seq.generateRandomInt(6);
        Order order = new Order(orderSn, 0.00, 0.00, productId, customerId, 1, 3, new Date(), product.getSource(), product.getPropId(),count);
        order.setPoint(totalPoint);
        orderService.save(order);
        Integer resultPoint = customer.getPoint()-totalPoint;
        customer.setPoint(resultPoint);
        CustomerPoint customerPoint = new CustomerPoint(customerId, activityProduct.getPoint(), productId, 2, new Date());
        customerPointService.save(customerPoint);
        CustomerAssets customerAssets = new CustomerAssets(customerId, productId, product.getType(), new Date(), null,4, null);
        customerAssetsService.save(customerAssets);
        customerService.updateCustomerAssets(product.getType(), productId, customerId);
        customerService.updateById(customer);
    }
    class NotifyHandler implements Runnable {

        private String outTradeNo;
        private String tradeStatus;
        private String tradeNo;

        public NotifyHandler(String outTradeNo, String tradeStatus, String tradeNo) {
            this.outTradeNo = outTradeNo;
            this.tradeStatus = tradeStatus;
            this.tradeNo = tradeNo;
        }

        @Override
        public void run() {
            int state = StringUtils.equals(tradeStatus, "TRADE_SUCCESS")|| StringUtils.equals(tradeStatus,"TRADE_FINISHED")? 1 : 2;
            updateOrder(state, tradeNo, outTradeNo);
        }
    }

    @Override
    public AlipayTradeAppPayResponse createAlipayOrder(int productId) throws Exception {
        String orderSn = DateUtils.dateTimeNow()+ Seq.generateRandomInt(6);
        Product product = productService.getById(productId);
        long customerId = SecurityUtils.getLoginUser().getUserId();
        int count = 1;
        double totalFee = product.getPrice()*count;
        Order order = new Order(orderSn, product.getPrice(), totalFee, productId, customerId, 0, 2, new Date(), product.getSource(), product.getPropId(),count);
        orderService.save(order);
        AlipayTradeAppPayResponse response = AlipayTradeAppPay.pay(orderSn, product.getName(), totalFee+"",notifyUrl+"/api/notify/alipay");
        return response;
    }

    private void updateOrder(int status,String tradeNo, String orderSn){
        orderService.update(new LambdaUpdateWrapper<Order>()
                .set(Order::getStatus,status).set(Order::getPayTime,new Date()).set(Order::getTradeNo,tradeNo)
                .eq(Order::getOrderSn,orderSn));
        if(status == 2){
            return;
        }
        Order order = orderService.getOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderSn, orderSn));
        CustomerAssets customerAssets = new CustomerAssets(order.getCustomerId(), order.getProductId(), ProductType.MV.type, new Date(), null,3, null);
        customerAssetsService.save(customerAssets);
        customerService.updateCustomerAssets(ProductType.MV.type, order.getProductId(), order.getCustomerId());
    }

}
